﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TPA.DataAccess;

namespace TVProgramAnalyst.Helper
{
    public  static class TimelineHelper
    {
        public static Program CreateProgramfromKeyPoint(KeyPoint kp)
        {
             TPA.DataAccess.Program target = new TPA.DataAccess.Program()
                        {
                            Id = Guid.NewGuid(),
                            Name = kp.Label,
                            EnglishName = Helper.GB2PY.getAllPY(kp.Label)
                        };
                        if (kp.Type == KeyPointType.Program)
                            target.SubcategoryId = global.Default.Program_FormalProgram_DefaultSubCategoryId;
                        else
                            target.SubcategoryId = global.Default.Program_Advertisment_DefaultSubCategoryId;
            return target;
        }
        
        public static TimelineSegment ConvertToTimelineSegment(KeyPoint kp, Program p)
        {
            TimelineSegment td = new TimelineSegment()
            {
                //Id=Guid.NewGuid(),
                ProgramID = p.Id,
                AudienceMeasurement = kp.AudienceMeasurement,
                ChannelName = kp.Channel,
                EndDateTime = kp.DateTimeOut,
                StartDateTime = kp.DateTimeIn,
                BroadcastType = ""
             };
            if (kp.Type == KeyPointType.Program)
            {
                td.MarketShare = kp.MarketShare;
            }
            else
            {
                td.Price = kp.MarketShare;
            }
            return td;
        }

        /// <summary>
        /// Join key point with conditions.
        /// </summary>
        /// <param name="timeline">timeline</param>
        /// <param name="kp">a KeyPoint object which would be added to the timeline</param>
        public static void JoinKeyPoint(List<KeyPoint> timeline, KeyPoint kp)
        {
            KeyPoint next = new KeyPoint() { Channel = kp.Channel, AudienceMeasurement = kp.AudienceMeasurement, DateTimeIn = kp.DateTimeIn, DateTimeOut = kp.DateTimeOut, Label = kp.Label, MarketShare = kp.MarketShare, Priority = kp.Priority, Type = kp.Type };
            //join points;
            if (timeline.Count == 0)
            {
                timeline.Add(next);
                return;
            }
            KeyPoint current = timeline.Last();
            //Add next directly, if align with transmission
            if (next.Label == "End of Transmission" || next.Label == "Start of Transmission" || current.Label == "End of Transmission" || current.Label == "Start of Transmission")
            {
                if (next.Label == "Start of Transmission" && next.DateTimeIn == current.DateTimeIn)
                {
                    timeline.Insert(timeline.Count - 1, next);
                }
                else
                {
                    timeline.Add(next);
                }
                return;
            }
            if (current.Type != next.Type)
            {
                //check join type
                int compareResult = 0;
                compareResult = CompareLogKeyPoints(current, next);

                //handle join type
                #region handle join type
                switch (compareResult)
                {
                    case 1://remove the KeyPoint whose Type is program
                        if (current.Type == KeyPointType.Program && !current.Priority)
                        {
                            timeline.Remove(current);
                            timeline.Add(next);
                        }
                        break;
                    case 2://split next
                        KeyPoint kp2 = new KeyPoint()
                        {
                            Label = next.Label,
                            Type = next.Type,
                            DateTimeOut = DateTime.Parse(next.DateTimeOut.ToString()),
                            MarketShare = next.MarketShare,
                            Channel = next.Channel,
                            AudienceMeasurement = next.AudienceMeasurement,
                            DateTimeIn = DateTime.Parse(current.DateTimeOut.ToString())
                        };
                        next.DateTimeOut = DateTime.Parse(kp2.DateTimeIn.ToString());
                        if ((current.Type == KeyPointType.Program && !current.Priority)||next.Priority)
                        {
                            //replace program with adv
                            timeline.Remove(current);
                            timeline.Add(next);
                            timeline.Add(kp2);
                        }
                        else
                        {
                            timeline.Add(kp2);
                        }
                        break;
                    case 3://split current
                        KeyPoint kp3 = new KeyPoint()
                        {
                            Label = current.Label,
                            Type = current.Type,
                            DateTimeOut = DateTime.Parse(current.DateTimeOut.ToString()),
                            DateTimeIn = DateTime.Parse(next.DateTimeOut.ToString()),
                            AudienceMeasurement = current.AudienceMeasurement,
                            Channel = current.Channel,
                            MarketShare = current.MarketShare
                        };
                        current.DateTimeOut = DateTime.Parse(kp3.DateTimeIn.ToString());
                        if ((current.Type == KeyPointType.Program && !current.Priority) || next.Priority)
                        {
                            //replace program with adv
                            timeline.Remove(current);
                            timeline.Add(next);
                            timeline.Add(kp3);
                        }
                        else
                        {
                            timeline.Add(kp3);
                        }
                        break;
                    case 5:
                        KeyPoint kp5 = new KeyPoint()
                        {
                            Label = "技术调试",
                            DateTimeOut = next.DateTimeIn,
                            DateTimeIn = current.DateTimeOut,
                            Type = KeyPointType.Program,
                            AudienceMeasurement = 0,
                            Channel = current.Channel,
                            MarketShare = 0
                        };
                        timeline.Add(kp5);
                        timeline.Add(next);
                        break;
                    case 6: //current must be program
                        KeyPoint kp6 = new KeyPoint()
                        {
                            Label = next.Label,
                            MarketShare = next.MarketShare,
                            Channel = next.Channel,
                            AudienceMeasurement = next.AudienceMeasurement,
                            Type = next.Type,
                            DateTimeOut = DateTime.Parse(current.DateTimeOut.ToString()),
                            DateTimeIn = DateTime.Parse(next.DateTimeIn.ToString())
                        };
                        current.DateTimeOut = DateTime.Parse(kp6.DateTimeIn.ToString());
                        next.DateTimeIn = DateTime.Parse(kp6.DateTimeOut.ToString());
                        timeline.Add(kp6);
                        timeline.Add(next);
                        break;
                    case 7: //current must be program
                        KeyPoint kp7 = new KeyPoint()
                        {
                            DateTimeOut = DateTime.Parse(current.DateTimeOut.ToString()),
                            DateTimeIn = DateTime.Parse(next.DateTimeOut.ToString()),
                            Type = current.Type,
                            AudienceMeasurement = current.AudienceMeasurement,
                            Channel = current.Channel,
                            MarketShare = current.MarketShare,
                            Label = current.Label
                        };
                        current.DateTimeOut = DateTime.Parse(next.DateTimeIn.ToString());
                        timeline.Add(next);
                        timeline.Add(kp7);
                        break;
                    case 8: //current must be program
                        current.DateTimeOut = next.DateTimeIn;
                        timeline.Add(next);
                        break;
                    case 9: //current must be adv
                        KeyPoint kp9 = new KeyPoint()
                        {
                            DateTimeOut = DateTime.Parse(current.DateTimeOut.ToString()),
                            DateTimeIn = DateTime.Parse(next.DateTimeIn.ToString()),
                            Type = current.Type,
                            AudienceMeasurement = current.AudienceMeasurement,
                            Channel = current.Channel,
                            MarketShare = current.MarketShare,
                            Label = current.Label
                        };
                        current.DateTimeOut = DateTime.Parse(kp9.DateTimeIn.ToString());
                        next.DateTimeIn = DateTime.Parse(kp9.DateTimeOut.ToString());
                        timeline.Add(kp9);
                        timeline.Add(next);
                        break;
                    case 10: //current must be adv
                        //do nothing
                        break;
                    case 11: //current must be adv
                        //do nothing
                        break;
                    case 12: //split current to kp12, remove current, add next ,add kp12
                        KeyPoint kp12 = new KeyPoint()
                        {
                            Label = current.Label,
                            Type = current.Type,
                            DateTimeOut = DateTime.Parse(current.DateTimeOut.ToString()),
                            DateTimeIn = DateTime.Parse(next.DateTimeOut.ToString()),
                            AudienceMeasurement = current.AudienceMeasurement,
                            Channel = current.Channel,
                            MarketShare = current.MarketShare
                        };
                        timeline.Remove(current);
                        timeline.Add(next);
                        timeline.Add(kp12);
                        break;
                    case 13: //split next to kp 13, remove current, add next, add kp13
                        KeyPoint kp13 = new KeyPoint()
                        {
                            Label = next.Label,
                            Type = next.Type,
                            DateTimeOut = DateTime.Parse(next.DateTimeOut.ToString()),
                            MarketShare = next.MarketShare,
                            Channel = next.Channel,
                            AudienceMeasurement = next.AudienceMeasurement,
                            DateTimeIn = DateTime.Parse(current.DateTimeOut.ToString())
                        };
                        next.DateTimeOut = DateTime.Parse(kp13.DateTimeIn.ToString());
                        timeline.Remove(current);
                        timeline.Add(next);
                        timeline.Add(kp13);
                        break;
                    case 14: //remove current, add next
                        timeline.Remove(current);
                        timeline.Add(next);
                        break;
                    default:
                        timeline.Add(next);
                        break;
                }
                #endregion
            }
            else
                timeline.Add(next);
        }

        /// <summary>
        /// Compare KeyPoints.
        /// return value:
        /// 0: add next item directly.
        /// 1:
        /// 2:
        /// 3:
        /// 4: nothing need to do
        /// 5:
        /// 6
        /// 7
        /// 8
        /// 9
        /// 10
        /// 11
        /// 12: next.datetimin earlier than current.datetimein
        /// 13
        /// 14
        /// </summary>
        /// <param name="current">the last item of the timeline</param>
        /// <param name="next">the item would be added to timeline</param>
        /// <returns>join type</returns>
        public static int CompareLogKeyPoints(KeyPoint current, KeyPoint next)
        {
            if (current.DateTimeIn == next.DateTimeIn)
            {
                if (current.DateTimeOut == next.DateTimeOut)
                    return 1;//remove the KeyPoint whose Type is program
                else if (current.DateTimeOut < next.DateTimeOut)
                    return 2;//split next
                else if (current.DateTimeOut > next.DateTimeOut)
                    return 3;//split current
                else
                    return 0;
            }
            else if (current.DateTimeIn < next.DateTimeIn)
            {
                if (current.Type == KeyPointType.Program)
                {
                    if (current.DateTimeOut < next.DateTimeIn)
                        return 5;
                    else if (current.DateTimeOut > next.DateTimeIn && current.DateTimeOut < next.DateTimeOut)
                        return 6;
                    else if (current.DateTimeOut > next.DateTimeOut)
                        return 7;
                    else if (current.DateTimeOut == next.DateTimeOut)
                        return 8;
                    else
                        return 0;
                }
                else if (current.Type == KeyPointType.Advertisement)
                {
                    if (next.DateTimeIn > current.DateTimeOut)
                        return 5;
                    else if (next.DateTimeIn < current.DateTimeOut && next.DateTimeOut > current.DateTimeOut)
                        return 9;
                    else if (next.DateTimeOut < current.DateTimeOut)
                        return 10;
                    else if (next.DateTimeOut == current.DateTimeOut)
                        return 11;
                    else
                        return 0;
                }
                else
                    return 0;
            }
            else//current.DateTimeIn > next.DateTimeIn
            {
                   if (next.DateTimeOut < current.DateTimeOut)
                        return 12;
                    else if (next.DateTimeOut > current.DateTimeOut)
                        return 13;
                    else
                        return 14;
            }
                
        }
    }
}
